package com.fingard.crypto;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

import com.fingard.text.StringHelper;
import com.fingard.xml.XElement;

/**DSP内部加解密使用（DSP配置）*/
public class InnerCipher {
	private String _Key = "#$fH|K;S3.lK1ggp`@=ok\"95k_*%4547d~gj|y!!fd)*(&^%NLrKh:ASDfd4546h6i;;!-+);)8K8k,cDd'Q60?!#bFDfd)Q60?!#b";
    private String _IV = "+>~`-G<N6S3~lK1rK,hASH_%H\"m~DDF*nN<Ad`f[op-0934m5(&/>:;.HHnm]>?]/'fa,sdf4IUYgg*-_^$.,dflmfAcSHa1&_KEY?!#";
    
    private String _ExtraKey1 = "{)9+|][{'p}lKub8340&^%~@j65v__.<?.0*7h98-+";
    private String _ExtraKey2 = "(8~DDF*nNYn)9{]{'_\"+(&^+=@~!1m`+=.<NHC8-83Fdc:'";
    
    private Cipher cipherEn;
    private Cipher cipherDe;
    
    public InnerCipher() throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, InvalidKeyException, InvalidAlgorithmParameterException{
    	byte[] bytesKey = getLegalKey(_Key+_ExtraKey1);
        byte[] bytesIV = getLegalIV(_IV+_ExtraKey2);
        
        SecretKeySpec deskey = new SecretKeySpec(bytesKey, "AES");
        IvParameterSpec ivps = new IvParameterSpec(bytesIV);

        cipherEn = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipherEn.init(Cipher.ENCRYPT_MODE, deskey, ivps);
        
        cipherDe = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipherDe.init(Cipher.DECRYPT_MODE, deskey, ivps);

    }
    
    /**从XElement节点取得明文，返回字符串，根据属性encrypted，为true需要解密
     * @throws UnsupportedEncodingException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException */
    public String getFromXeAsStr(XElement pXe) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    	String reVal = "";
    	if(pXe!=null){
    		if(pXe.getAttrValueAsBool("encrypted")){
    			return Decrypt(pXe.innerText);
    		}else{
    			return pXe.innerText;
    		}
    	}
    	return reVal;
    }
    
    /**从XElement节点取得明文，返回boolean值，根据属性encrypted，为true需要解密
     * @throws UnsupportedEncodingException 
     * @throws BadPaddingException 
     * @throws IllegalBlockSizeException */
    public boolean getFromXeAsBool(XElement pXe) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    	String str = getFromXeAsStr(pXe).toLowerCase();
    	if("true".equals(str) || "1".equals(str)){
    		return true;
    	}
    	return false;
    }
    
    /**加密*/
    public String Encrypt(String pPlain) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    	byte[] bytesPlain = pPlain.getBytes("ASCII");
    	byte[] cipherBytes = cipherEn.doFinal(bytesPlain);
    	return Base64.encodeBase64String(cipherBytes);
    }
    
    /**解密*/
    public String Decrypt(String pCipherBase64) throws IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
    	byte[] bytesCipher = Base64.decodeBase64(pCipherBase64);
    	byte[] plainBytes = cipherDe.doFinal(bytesCipher);
    	return new String(plainBytes,0,plainBytes.length,"ASCII");
    }
    
    private static byte[] getLegalKey(String Key) throws UnsupportedEncodingException{
        return getLegal(Key, 128, 128, 64);
    }

    private static byte[] getLegalIV(String Key) throws UnsupportedEncodingException{
        return getLegal(Key, 128, 128, 64);
    }
    
    private static byte[] getLegal(String Key, int MinSize, int MaxSize, int SkipSize) throws UnsupportedEncodingException
    {
    	byte[] keyBytes = Key.getBytes("ASCII");
        int KeySize = keyBytes[0];
        int LegalMinSize = MinSize / 8;
        int LegalMaxSize = MaxSize / 8;
        int LegalSkipSize = SkipSize / 8;

        if (KeySize < LegalMinSize)
        {
        	Key = StringHelper.padRight(Key, LegalMinSize, '^');
        	keyBytes = Key.getBytes("ASCII");
        	KeySize = keyBytes[0];
        }

        if (LegalSkipSize == 0)
        {
        	byte[] retBytes = new byte[LegalMaxSize];
        	System.arraycopy(keyBytes, 0, retBytes, 0, LegalMaxSize);
            return retBytes;
        }
        int Size = LegalMinSize;
        if (KeySize >= LegalMaxSize)
        {
            while (KeySize > Size && Size < LegalMaxSize)
                Size += LegalSkipSize;
        }
        else
        {
            while (KeySize < Size && Size > LegalMinSize)
                Size -= LegalSkipSize;
        }
        byte[] retBytes = new byte[Size];
    	System.arraycopy(keyBytes, 0, retBytes, 0, Size);
        return retBytes;
    }
}
